package com.ilxqx.framework.security.filter;

import com.ilxqx.framework.security.config.SecurityConfigProperties;
import com.ilxqx.framework.security.exception.ValidationException;
import com.ilxqx.framework.security.validation.Validation;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

/**
 * 极验验证过滤器
 * @author venus
 */
public class GeeTestValidationFilter extends OncePerRequestFilter {

	/**
	 * 安全配置
	 */
	private SecurityConfigProperties securityConfigProperties;

	/**
	 * 验证失败处理器
	 */
	private AuthenticationFailureHandler authenticationFailureHandler;

	/**
	 * 验证服务类
	 */
	private Validation validation;

	public GeeTestValidationFilter(SecurityConfigProperties securityConfigProperties, AuthenticationFailureHandler authenticationFailureHandler, Validation validation) {
		this.securityConfigProperties = securityConfigProperties;
		this.authenticationFailureHandler = authenticationFailureHandler;
		this.validation = validation;
	}

	/**
	 * Same contract as for {@code doFilter}, but guaranteed to be
	 * just invoked once per request within a single request thread.
	 * See {@link #shouldNotFilterAsyncDispatch()} for details.
	 * <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
	 * default ServletRequest and ServletResponse ones.
	 *
	 * @param request 请求对象
	 * @param response 响应对象
	 * @param filterChain 过滤链
	 */
	@Override
	protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
		String uri = request.getRequestURI();
		boolean intercept = StringUtils.equalsIgnoreCase(request.getMethod(), "post")
			&& (StringUtils.equals(uri, this.securityConfigProperties.getLoginProcessingUrl())
			|| Arrays.stream(securityConfigProperties.getValidationFilterUrls()).anyMatch(url -> StringUtils.equals(uri, url)));
		if (intercept) {
			// 拦截做验证处理
			try {
				validate(request);
			} catch (ValidationException e) {
				// 验证失败了
				this.authenticationFailureHandler.onAuthenticationFailure(request, response, e);
				return;
			}
		}

		filterChain.doFilter(request, response);
	}

	/**
	 * 验证处理
	 * @param request 请求对象
	 */
	private void validate(HttpServletRequest request) {
		boolean result = this.validation.validate(request);
		if (!result) {
			throw new ValidationException("验证失败");
		}
	}

}
